package com.youqu.common.model;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.hashids.Hashids;
import org.joda.time.DateTime;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.cjw.model.DBMap;
import com.jfinal.kit.HashKit;
import com.jfinal.kit.JsonKit;
import com.jfinal.kit.LogKit;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.jfinal.weixin.sdk.api.PaymentApi;
import com.jfinal.weixin.sdk.api.PaymentApi.TradeType;
import com.jfinal.weixin.sdk.kit.PaymentKit;
import com.utils.PathUtils;
import com.youqu.common.model.base.BaseYqOrder;
import com.zhenyi.core.tencent.map.MapUtils;
import com.zhenyi.core.wechatPay.PayUtils;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.util.RandomUtil;

/**
 * Generated by JFinal.
 */
@SuppressWarnings("serial")
public class YqOrder extends BaseYqOrder<YqOrder> {

	/**
	 * 支付方式_微信支付
	 */
	public static final Integer METHOD_WECHAT = 1;
	/**
	 * 支付方式_支付宝
	 */
	public static final Integer METHOD_ALI = 2;

	public YqOrder() {
		// setAppId(APP_ID);
		// setMchId(PARTNER);
	}

	public YqOrder(YqApp app) {
		setAppId(app.getWechatMiniAppId());
		setMchId(app.getWechatPartner());
		setProjectAppId(app.getId());
	}

	/**
	 * 更新支付下单方式
	 * 
	 * @param shopId
	 * @param method
	 */
	public void updatePayInfo(Long shopId, int method) {
	}

	/**
	 * 订单类型未知
	 */
	public static final Integer TYPE_NONE = 0;
	/**
	 * 订单类型商品
	 */
	public static final Integer TYPE_PRODUCT = 1;
	/**
	 * 订单类型团购
	 */
	public static final Integer TYPE_GROUP = 2;
	/**
	 * 订单类型第三方
	 */
	public static final Integer TYPE_THIRD = 3;
	/**
	 * 充值
	 */
	public static final Integer TYPE_CHARGE = 4;

	/**
	 * 0.未支付
	 */
	public static final Integer STATUS_NOTPAY = 0;
	/**
	 * 1.已支付
	 */
	public static final Integer STATUS_PAID = 1;
	/**
	 * -1,退款
	 */
	public static final Integer STATUS_REFUND = -1;
	/**
	 * -2.关闭
	 */
	public static final Integer STATUS_CLOSED = -2;
	/**
	 * -3.未支付成功
	 */
	public static final Integer STATUS_PAYFAIL = -3;

	public static final Hashids MIN_HASHID = new Hashids("youqu", 2);
	public static final Hashids LONG_HASHID = new Hashids("youqu", 6);

	public static final String SUCCESS = "SUCCESS";
	public static final String REFUND = "REFUND";
	public static final String NOTPAY = "NOTPAY";
	public static final String CLOSED = "CLOSED";
	public static final String REVOKED = "REVOKED";
	public static final String USERPAYING = "USERPAYING";
	public static final String PAYERROR = "PAYERROR";

	// protected final String APP_ID = PropKit.get("YQ_APP_ID", "");
	// protected final String APP_SECRET = PropKit.get("YQ_APP_SECRET", "");
	// protected final String PARTNER = PropKit.get("YQ_PARTNER", "");
	// protected final String NOTIFY_URL = PropKit.get("YQ_NOTIFY_URL", "");
	// protected final String PARTNER_KEY = PropKit.get("YQ_PARTNER_KEY", "");
	// protected final String REFUND_NOTIFY_URL =
	// PropKit.get("YQ_REFUND_NOTIFY_URL", "");
	// protected final String SSL_PATH = PathUtils.getFile("cert", APP_ID,
	// "apiclient_cert.p12");
	// protected final PayUtils payUtils = new PayUtils(APP_ID, PARTNER,
	// PARTNER_KEY, SSL_PATH);

	public static final YqOrder dao = new YqOrder();

	private final boolean DEBUG = PropKit.getBoolean("devMode", true);

	public static final String genTradeNo() {
		String outTradeNo = DateUtil.now();
		outTradeNo = outTradeNo.replace("-", "");
		outTradeNo = outTradeNo.replace(" ", "");
		outTradeNo = outTradeNo.replace(":", "");
		return outTradeNo;
	}

	public void updateOrderInfo() {
		YqOrderInfo orderInfo = YqOrderInfo.dao.findById(getId());
		if (orderInfo == null) {
			return;
		}
		orderInfo.setStatus(getStatus());
		orderInfo.update();
	}

	/**
	 * 订单退款
	 * 
	 * @param fee
	 * @return
	 */
	public Map<String, String> refund(String fee) {
		YqOrder order = this;
		String out_trade_no = order.getOutTradeNo();
		String refundNo = out_trade_no + "-refund-" + RandomUtil.randomString(3);
		return refund(fee, refundNo);
	}

	public void refundAli() {

	}

	public Map<String, String> refundWechat(String fee, String refundNo, Long projectAppId) {
		String appId = getWechatMiniAppId();
		String partner = getWechatPartner();
		String partnerKey = getWechatPartnerKey();
		String sslPath = PathUtils.getFile("cert", appId, "apiclient_cert.p12");
		String refundNotifyUrl = getWechatPayRefundNotifyUrl();
		YqOrder order = this;
		String out_trade_no = order.getOutTradeNo();
		Map<String, String> query = PaymentApi.queryByOutTradeNo(appId, partner, partnerKey, out_trade_no);
		// if (PropKit.getBoolean("devMode", false)) {
		// System.out.println(JsonKit.toJson(query));
		// }
		String trade_state = query.get("trade_state");
		if (!("REFUND".equals(trade_state) || "SUCCESS".equals(trade_state))) {
			LogKit.info("订单支付状态非SUCCESS");
			return null;
		}
		String total_fee = order.getTotalFee();
		String refundFee = StrKit.isBlank(fee) ? order.getPaid() + "" : fee;
		PayUtils payUtils = new PayUtils(appId, partner, partnerKey, sslPath);
		Map<String, String> refund = payUtils.refundOrderNo(out_trade_no, total_fee, refundFee, refundNo,
				refundNotifyUrl);
		// System.out.println(refund);
		// boolean flag = PayUtils.isXMLSuccess(refund);
		// System.out.println(JsonKit.toJson(refund));
		return refund;

	}

	/**
	 * 订单退款
	 * 
	 * @param fee
	 * @param refundNo
	 * @return
	 */
	public Map<String, String> refund(String fee, String refundNo) {
		return refundWechat(fee, refundNo, getProjectAppId());
	}

	private String getWechatMiniAppId() {
		return getApp().getWechatMiniAppId();
	}

	private String getWechatPartner() {
		return getApp().getWechatPartner();
	}

	private String getWechatPartnerKey() {
		return getApp().getWechatPartnerKey();
	}

	private String getWechatPayNotifiyUrl() {
		return getApp().getWechatPayNotifiyUrl();
	}

	private String getWechatPayRefundNotifyUrl() {
		return getApp().getWechatPayRefundNotifyUrl();
	}

	/**
	 * 更新微信订单
	 * 
	 * @return
	 */
	protected Map<String, String> updateWechatOrderStatus() {

		String appId = getWechatMiniAppId();
		String partner = getWechatPartner();
		String partnerKey = getWechatPartnerKey();

		YqOrder order = this;
		Map<String, String> query = PaymentApi.queryByOutTradeNo(appId, partner, partnerKey, getOutTradeNo());
		System.out.println(JsonKit.toJson(query));
		String sign = query.get("sign");
		String mySign = PaymentKit.createSign(query, partnerKey);
		if (!mySign.equals(sign)) {
			return null;
		}
		String trade_state = query.get("trade_state");
		if (PropKit.getBoolean("devMode", false)) {
			LogKit.info("trade_state: " + trade_state);
			System.out.println(JsonKit.toJson(query));
		}
		if (trade_state == null) {
			return null;
		}
		order.setTradeState(trade_state);
		if (trade_state.equals("SUCCESS")) {
			order.setStatus(STATUS_PAID);
		} else if (trade_state.equals("REFUND")) {
			order.setStatus(STATUS_REFUND);
		} else if (trade_state.equals("NOTPAY")) {
			order.setStatus(STATUS_NOTPAY);
		} else if (trade_state.equals("CLOSED")) {
			order.setStatus(STATUS_CLOSED);
		} else if (trade_state.equals("REVOKED")) {
			order.setStatus(STATUS_PAYFAIL);
		} else if (trade_state.equals("USERPAYING")) {
			order.setStatus(STATUS_NOTPAY);
		} else if (trade_state.equals("PAYERROR")) {
			order.setStatus(STATUS_PAYFAIL);
		}
		order.update();
		return query;

	}

	/**
	 * 更新订单
	 * 
	 * @return
	 */
	public Map<String, String> updateOrderStatus() {
		return updateWechatOrderStatus();
	}

	/**
	 * 关闭微信订单
	 * 
	 * @return
	 */
	protected boolean closeWechatOrder() {
		updateWechatOrderStatus();
		if (!"NOTPAY".equals(getTradeState())) {
			LogKit.info("订单非未支付");
			return false;
		}
		String appId = getWechatMiniAppId();
		String partner = getWechatPartner();
		String partnerKey = getWechatPartnerKey();

		Map<String, String> result = PaymentApi.closeOrder(appId, partner, partnerKey, getOutTradeNo());
		LogKit.info(JsonKit.toJson(result));
		if (DEBUG) {
			LogKit.info(JsonKit.toJson(result));
		}
		if (!PayUtils.isXMLSuccess(result)) {
			LogKit.info("关闭失败");
			return false;
		}
		updateOrderStatus();
		setStatus(STATUS_CLOSED);
		return true;
	}

	/**
	 * 关闭订单
	 * 
	 * @return
	 */
	public boolean closeOrder() {
		return closeWechatOrder();
	}

	/**
	 * 根据关键信息下单(JSAPI),微信
	 * 
	 * @param ip
	 * @param appid
	 * @param partner
	 * @param partnerKey
	 * @param notifyUrl
	 * @return
	 */
	public boolean pushOrder(String ip, String appid, String partner, String partnerKey, String notifyUrl) {

		if (StrKit.notBlank(getPrepayId())) {
			return true;
		}
		// String nonce_str = System.currentTimeMillis() / 1000 + "";
		String nonce_str = RandomUtil.randomString(32);
		String tradeNo = getOutTradeNo();

		Map<String, String> params = new HashMap<String, String>();
		params.put("appid", appid);
		params.put("mch_id", partner);
		params.put("body", getBody());
		params.put("out_trade_no", tradeNo);
		params.put("total_fee", getTotalFee());
		if (StrKit.isBlank(ip)) {
			ip = "127.0.0.1";
		}
		if (DEBUG) {
			ip = "127.0.0.1";
		}
		params.put("spbill_create_ip", ip);
		params.put("trade_type", TradeType.JSAPI.name());
		params.put("nonce_str", nonce_str);
		params.put("notify_url", notifyUrl);
		params.put("openid", getOpenid());
		params.put("sign_type", "MD5");
		Date expire = new DateTime().plusMinutes(5).toDate();
		params.put("time_expire", DateUtil.format(expire, "yyyyMMddHHmmss"));
		String attach = getAttach();
		if (StrKit.notBlank(attach)) {
			params.put("attach", attach);
		}
		LogKit.info("PaymentKit: " + PaymentKit.toXml(params));
		// String sign = PaymentKit.createSign(params, partnerKey);

		String stringA = PaymentKit.packageSign(params, false);
		// LogKit.info("stringA: " + stringA);
		String stringSignTemp = stringA + "&key=" + partnerKey;
		// LogKit.info("stringSignTemp: " + stringSignTemp);
		String sign = HashKit.md5(stringSignTemp).toUpperCase();
		// LogKit.info("sign: " + sign);

		params.put("sign", sign);
		String xmlResult = PaymentApi.pushOrder(params);
		Map<String, String> result = PaymentKit.xmlToMap(xmlResult);
		// LogKit.info("sign" + sign);
		// LogKit.info("partnerKey" + partnerKey);

		if (DEBUG) {
			LogKit.info("NOTIFY_URL: " + notifyUrl);
			LogKit.info("APP_ID: " + appid);
			LogKit.info("PARTNER: " + partner);
			LogKit.info("PARTNER_KEY: " + partnerKey + " - " + partnerKey.length());
			LogKit.info("trade_type: " + TradeType.JSAPI.name());
		}
		if (!PayUtils.isXMLSuccess(result)) {
			LogKit.error(PaymentKit.toXml(params));
			LogKit.info(xmlResult);
			return false;
		}

		String prepay_id = result.get("prepay_id");
		// DateTime dateTime = new DateTime();
		// String timeStamp = dateTime.toDate().getTime() / 1000 + "";
		// String signString = "appId=" + APP_ID + "&nonceStr=" + nonce_str +
		// "&package=prepay_id=" + prepay_id
		// + "&signType=MD5&timeStamp=" + timeStamp + "&key=" + PARTNER_KEY;
		// signString = HashKit.md5(signString).toUpperCase();
		// DBMap map = new DBMap();
		// map.put("result", result);
		// map.put("sign", signString);
		// map.put("timeStamp", timeStamp);
		// map.put("nonce_str", nonce_str);
		// order.setPrepayId(prepay_id);
		// order.update();
		// renderResult(map, "pay", 201);
		// return prepay_id;
		setTradeType(TradeType.JSAPI.name());
		setExpires(expire);
		setPrepayId(prepay_id);
		return true;

	}

	/**
	 * 使用商户支付信息下单(JSAPI)
	 * 
	 * @param ip
	 * @param shopId
	 * @return
	 */
	public boolean pushOrder(String ip, Long shopId) {
		YqShop shop = YqShop.dao.findById(shopId);
		if (shop == null) {
			return false;
		}
		String appid = getWechatMiniAppId();
		if (StrKit.isBlank(appid)) {
			LogKit.info("shop appid is null");
			return false;
		}
		String partner = getWechatPartner();
		if (StrKit.isBlank(partner)) {
			LogKit.info("shop partner is null");
			return false;
		}
		String partnerKey = getWechatPartnerKey();
		if (StrKit.isBlank(partnerKey)) {
			LogKit.info("shop partnerKey is null");
			return false;
		}
		return pushOrder(ip, appid, partner, partnerKey, getWechatPayNotifiyUrl());
	}

	/**
	 * 微信下单,默认使用内置支付信息(有趣)
	 * 
	 * @param ip
	 * @return
	 */
	public boolean pushOrder(String ip) {
		String appId = getWechatMiniAppId();
		String partner = getWechatPartner();
		String partnerKey = getWechatPartnerKey();
		return pushOrder(ip, appId, partner, partnerKey, getWechatPayNotifiyUrl());
	}

	public void pushAliOrder(String APP_ID, String APP_PRIVATE_KEY) {
	}

	/**
	 * 支付宝支付 https://docs.open.alipay.com/54/106370/
	 */
	public void pushAliOrder() {
		String APP_ID = "2019041063847202";
		String path = PathUtils.getFile("cert", APP_ID, "key.pem");
		String content = new FileReader(path).readString();
		System.out.println(content);
		String APP_PRIVATE_KEY = content;
		String CHARSET = "utf8";
		String ALIPAY_PUBLIC_KEY = new FileReader(
				PathUtils.getFile("cert", "alipay_public_key_sha256_2019041063847202.txt")).readString();
		System.out.println(ALIPAY_PUBLIC_KEY);
		String outtradeno = getOutTradeNo();
		// 实例化客户端
		AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", APP_ID,
				APP_PRIVATE_KEY, "json", CHARSET, ALIPAY_PUBLIC_KEY, "RSA2");
		// 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
		AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
		// SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
		AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
		model.setBody(getBody());
		model.setSubject(getDetail());
		model.setOutTradeNo(outtradeno);
		model.setTimeoutExpress("15m");
		model.setTotalAmount("0.01");
		model.setProductCode(getProductId());
		request.setBizModel(model);
		request.setNotifyUrl("http://release.zhen-yee.com/yq/api/ali/billPush/" + APP_ID);
		try {
			// 这里和普通的接口调用不同，使用的是sdkExecute
			AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
			String orderString = response.getBody();
			System.out.println("orderString: " + orderString);// 就是orderString
			setOrderString(orderString);
			update();
		} catch (AlipayApiException e) {
			e.printStackTrace();
		}
	}

	public DBMap getResponseData() {
		YqOrder order = this;
		DBMap map = new DBMap();
		map.put("body", order.getBody());
		map.put("detail", order.getDetail());
		map.put("goodsTag", order.getGoodsTag());
		map.put("productId", order.getProductId());
		map.put("data", order.getData());
		map.put("notifyUrl", order.getNotifyUrl());
		// map.put("mark", order.getMark());
		map.put("outTradeNo", order.getOutTradeNo());
		return map;
	}

	/**
	 * 获取商家与派送员的地图
	 * 
	 * @param targetLocation
	 * @return
	 */
	public String getShopUserMap(String targetLocation) {
		String defaultMap = "https://apis.map.qq.com/ws/staticmap/v2?key=U4HBZ-DYHRS-P3COG-6AAHE-OEFCV-ECFMY&labels=border:1|size:12|color:0x000000|bgcolor:0xFFFFFF|anchor:3|offset:0_-15|植绘配送|22.2533016204834,113.57396697998047&maptype=roadmap&markers=size:large|color:0xFFCCFF|icon:http://res.zhen-yee.com/res/www/img/favicon.png|22.2533016204834,113.57396697998047|22.250594075520834,113.58383978949652&size=600*600&sig=9721c3877f5271b70f5210d73a2bd03b";
		if (StrKit.isBlank(targetLocation)) {
			return defaultMap;
		}
		Long shopUserId = getShopUserId();
		if (shopUserId == null) {
			return defaultMap;
		}
		YqShopUser shopUser = YqShopUser.dao.findById(shopUserId);
		if (shopUser == null) {
			return defaultMap;
		}
		String location = shopUser.getLocation();
		if (StrKit.isBlank(location)) {
			return defaultMap;
		}
		String appKey = "U4HBZ-DYHRS-P3COG-6AAHE-OEFCV-ECFMY";
		String signKey = "jtuzfmTEDoUNzayknQwANPFl5Hnx8Au";
		String map = new MapUtils(appKey, signKey).getDeliverMap(targetLocation, location);
		return map;
	}

	public PayUtils getPayUtils() {
		YqApp app = getApp();
		String appId = app.getWechatMiniAppId();
		String partner = app.getWechatPartner();
		String partnetKey = app.getWechatPartnerKey();
		String sslPath = PathUtils.getFile("cert", appId, "apiclient_cert.p12");
		PayUtils payUtils = new PayUtils(appId, partner, partnetKey, sslPath);
		return payUtils;
	}

	public YqApp getApp() {
		return YqApp.dao.findByAppId(getProjectAppId());
	}
}
